package com.rojored.remote
{

import flash.utils.Dictionary;
import mx.rpc.AsyncToken;
import org.spicefactory.lib.reflect.ClassInfo;
import org.spicefactory.lib.reflect.Property;
import org.spicefactory.parsley.core.context.Context;
import org.spicefactory.parsley.core.context.provider.Provider
import org.spicefactory.parsley.core.messaging.MessageReceiverRegistry;
import org.spicefactory.parsley.core.messaging.receiver.CommandTarget;
import org.spicefactory.parsley.core.scope.ScopeName;
import org.spicefactory.parsley.processor.messaging.receiver.DefaultCommandTarget;

/**
 *  Handles DS / Parsley integration for the standard save, index and destroy
 *  operations.
 */
public class DSAction
{

    //--------------------------------------------------------------------------
    //
    //  Constructor
    //
    //--------------------------------------------------------------------------

    /**
     *  Constructor
     */
    public function DSAction()
    {
        super();
    }

    //--------------------------------------------------------------------------
    //
    //  Variables
    //
    //--------------------------------------------------------------------------

    /**
     *  @private
     */
    private var messageToItemPropertyMap:Dictionary = new Dictionary();

    //--------------------------------------------------------------------------
    //
    //  Properties
    //
    //--------------------------------------------------------------------------

    //--------------------------------------
    //  context
    //--------------------------------------

    [Inject]

    /**
     *  Parsley context
     */
    public var context:Context;

    //--------------------------------------
    //  delegate
    //--------------------------------------

    /**
     *  Handles all the DS persistance operations
     */
    public var delegate:DSDelegate;

    //--------------------------------------
    //  saveMessageType
    //--------------------------------------

    /**
     *  Gesture class for saving items.
     */
    public var saveMessageType:Class;

    //--------------------------------------
    //  getMessageType
    //--------------------------------------

    /**
     *  Gesture class for fetching individual items.
     */
    public var getMessageType:Class;

    //--------------------------------------
    //  deleteMessageType
    //--------------------------------------

    /**
     *  Gesture class for deleting items.
     */
    public var deleteMessageType:Class;

    //--------------------------------------
    //  indexMessageType
    //--------------------------------------

    /**
     *  Gesture class for requesting a list of items.
     */
    public var indexMessageType:Class;

    //--------------------------------------------------------------------------
    //
    //  Methods
    //
    //--------------------------------------------------------------------------

    /**
     *  @private
     */
    private function getPayloadName(classInfo:ClassInfo):String
    {
        var properties:Array = classInfo.getProperties();
        for each (var property:Property in properties)
        {
            if (property.hasMetadata("Payload"))
                return property.name;
        }

        throw new Error("No payload defined for class " +
            classInfo.getClass());

        return null;

    }

    //--------------------------------------------------------------------------
    //
    //  Message handlers
    //
    //--------------------------------------------------------------------------

    [Init]

    /**
     *  @private
     */
    public function initHandler():void
    {

        var messageReceiverRegistry:MessageReceiverRegistry =
            context.scopeManager.getScope(ScopeName.GLOBAL).messageReceivers;

        if (saveMessageType)
        {
            var saveMessageInfo:ClassInfo =
                ClassInfo.forClass(saveMessageType)

            messageToItemPropertyMap[saveMessageType] =
                getPayloadName(saveMessageInfo);

            messageReceiverRegistry.addCommand(
                new DefaultCommandTarget(Provider.forInstance(this),
                    "saveMessageHandler", undefined, saveMessageInfo));
        }

        if (deleteMessageType)
        {
            var deleteMessageInfo:ClassInfo =
                ClassInfo.forClass(deleteMessageType)

            messageToItemPropertyMap[deleteMessageType] =
                getPayloadName(deleteMessageInfo);

            messageReceiverRegistry.addCommand(
                new DefaultCommandTarget(Provider.forInstance(this),
                    "deleteMessageHandler", undefined,
                    ClassInfo.forClass(deleteMessageType)));
        }

        if (getMessageType)
        {
            var getMessageInfo:ClassInfo =
                ClassInfo.forClass(getMessageType)

            messageToItemPropertyMap[getMessageType] =
                getPayloadName(getMessageInfo);

            messageReceiverRegistry.addCommand(
                new DefaultCommandTarget(Provider.forInstance(this),
                    "getMessageHandler", undefined,
                    ClassInfo.forClass(getMessageType)));
        }

        if (indexMessageType)
            messageReceiverRegistry.addCommand(
                new DefaultCommandTarget(Provider.forInstance(this),
                    "indexMessageHandler", undefined,
                    ClassInfo.forClass(indexMessageType)));
    }

    /**
     *  @private
     */
    public function saveMessageHandler(msg:Object):AsyncToken
    {
        return delegate.save(msg[messageToItemPropertyMap[saveMessageType]]);
    }

    /**
     *  @private
     */
    public function indexMessageHandler(msg:Object):AsyncToken
    {
        return delegate.index(msg);
    }

    /**
     *  @private
     */
    public function getMessageHandler(msg:Object):AsyncToken
    {
        return delegate.get(msg[messageToItemPropertyMap[getMessageType]]);
    }

    /**
     *  @private
     */
    public function deleteMessageHandler(msg:Object):AsyncToken
    {
        return delegate.destroy(msg[messageToItemPropertyMap[deleteMessageType]]);
    }
}
}
